﻿using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using CollegeSim.CourseScheduler.Domain.DTO;
using CollegeSim.CourseScheduler.Domain.Interfaces;
using CollegeSim.CourseScheduler.Domain.Interfaces.Repositories;

namespace CollegeSim.CourseScheduler.Persistence
{
    // Author: Ryan Redburn
    // Project: Course Scheduler
    // Date: 2/5/2014

    #region [ Updates ]

    // Author: Ryan Redburn
    // Date: 2/22/2014
    // Revision: Introduced exception handling for invalid method arguments

    // Author: Ryan Redburn
    // Date: 2/26/2014
    // Revision: Added exception handling for unique constraints

    #endregion

    public class InstructorRepository : IInstructorRepository
    {
        #region [ Methods ]

        /// <summary>
        /// Returns all Instructors.
        /// </summary>
        /// <returns>IEnumerable of InstructorDto.</returns>
        public IEnumerable<InstructorDto> FindAll()
        {
            IEnumerable<InstructorDto> instructors;
            using (var context = new CollegeSimEntities())
            {
                instructors = Mapper.Map<IEnumerable<InstructorDto>>(context.Instructors);
            }

            return instructors;
        }

        /// <summary>
        /// Returns all Instructors with the given name.
        /// </summary>
        /// <param name="firstName">Instructor first name.</param>
        /// <param name="lastName">Instructor last name.</param>
        /// <returns>IEnumerable of InstructorDto.</returns>
        public IEnumerable<InstructorDto> FindByName(string firstName, string lastName)
        {
            if (!String.IsNullOrWhiteSpace(firstName) && !String.IsNullOrWhiteSpace(lastName))
            {
                IEnumerable<InstructorDto> instructors;

                using (var context = new CollegeSimEntities())
                {
                    instructors = Mapper.Map<IEnumerable<InstructorDto>>(context.Instructors
                        .Where(i => i.FirstName == firstName && i.LastName == lastName));
                }

                return instructors;
            }

            // Throw exception for invalid firstName value
            if (String.IsNullOrWhiteSpace(firstName))
            {
                throw new ArgumentNullException("firstName",
                    "firstName does not accept a null or empty string as an argument.");
            }

            // Throw exception for invalid lastName value
            if (String.IsNullOrWhiteSpace(lastName))
            {
                throw new ArgumentNullException("lastName",
                    "lastName does not accept a null or empty string as an argument.");
            }

            return null;
        }

        /// <summary>
        /// Returns an instructor with the given id. Returns a null InstructorDto if no Instructor with the given id is found.
        /// </summary>
        /// <param name="instructorId">Instructor integer id.</param>
        /// <returns>InstructorDto.</returns>
        public InstructorDto FindById(int instructorId)
        {
            // Throw exception on invalid instructorId value
            if (instructorId < 0)
                throw new ArgumentOutOfRangeException("instructorId",
                    "instructorId cannot be less than zero.");

            InstructorDto instructor;

            using (var context = new CollegeSimEntities())
            {
                instructor = Mapper.Map<InstructorDto>(context.Instructors
                    .SingleOrDefault(i => i.Id == instructorId));
            }

            return instructor;
        }

        /// <summary>
        /// Saves a new Instructor.
        /// </summary>
        /// <param name="newInstructor">New Instructor to save.</param>
        public void Insert(InstructorDto newInstructor)
        {
            // Throw exception for null dto
            if (newInstructor == null)
                throw new ArgumentNullException("newInstructor",
                    "newInstructor does not accept a null dto as an argument.");

            using (var context = new CollegeSimEntities())
            {
                context.Instructors.Add(Mapper.Map<Instructor>(newInstructor));
                context.SaveChanges();
            }
        }

        /// <summary>
        /// Updates an existing Instructor.
        /// </summary>
        /// <param name="instructorUpdate">Instructor to update.</param>
        public void Update(InstructorDto instructorUpdate)
        {
            // Throw exception for null dto
            if (instructorUpdate == null)
                throw new ArgumentNullException("instructorUpdate",
                    "instructorUpdate does not accept a null dto as an argument.");

            using (var context = new CollegeSimEntities())
            {
                var instructor = context.Instructors.SingleOrDefault(i => i.Id == instructorUpdate.Id);

                // Throws an exception if no matching entry is found
                if (instructor == null)
                    throw new InvalidOperationException("No entry matching the given instructor was found.");
                
                // Updates existing instructor
                instructor.FirstName = instructorUpdate.FirstName;
                instructor.LastName = instructorUpdate.LastName;
                instructor.PhoneNumber = instructorUpdate.PhoneNumber;
                instructor.Email = instructorUpdate.Email;
                instructor.OfficeNumber = instructorUpdate.OfficeNumber;

                context.SaveChanges();
            }
        }

        /// <summary>
        /// Deletes an existing Instructor.
        /// </summary>
        /// <param name="instructorDel">Instructor to delete.</param>
        public void Delete(InstructorDto instructorDel)
        {
            // Throw exception for null dto
            if (instructorDel == null)
                throw new ArgumentNullException("instructorDel",
                    "instructorDel does not accept a null dto as an argument.");

            using (var context = new CollegeSimEntities())
            {
                var instructor = context.Instructors.SingleOrDefault(i => i.Id == instructorDel.Id);

                // Throws an exception if no matching entry is found
                if (instructor == null)
                    throw new InvalidOperationException("No entry matching the given instructor was found.");

                context.Instructors.Remove(instructor);
                context.SaveChanges();
            }
        }

        #endregion
    }
}
